package com.minis.web.method.annotation;

import com.minis.beans.exception.BeansException;
import com.minis.beans.factory.annotation.Autowired;
import com.minis.web.bind.support.WebBindingInitializer;
import com.minis.web.bind.WebDataBinder;
import com.minis.web.bind.annotation.ResponseBody;
import com.minis.web.bind.support.WebDataBinderFactory;
import com.minis.web.context.WebApplicationContext;
import com.minis.web.method.HandlerMethod;
import com.minis.web.servlet.HandlerAdapter;
import com.minis.web.servlet.converter.HttpMessageConverter;
import com.minis.web.servlet.view.ModelAndView;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

/**
 * 处理器适配器，用于适配不同的处理
 */
public class RequestMappingHandlerAdapter implements HandlerAdapter {
    private WebApplicationContext wac;
    // 参数绑定
    private WebBindingInitializer wbi;
    // 返回值处理
    private HttpMessageConverter messageConverter;

    public RequestMappingHandlerAdapter() {
    }

    public RequestMappingHandlerAdapter(WebApplicationContext wac) {
        this.wac = wac;
        try {
//            AnnotationConfigWebApplicationContext awac = (AnnotationConfigWebApplicationContext) wac;
//            this.wbi = (WebBindingInitializer) awac.getParent().getBean("webBindingInitializer");
            // mvc 容器中找不到，会去 ioc 容器中找
            this.wbi = (WebBindingInitializer) this.wac.getBean("webBindingInitializer");
        } catch (BeansException e) {
            e.printStackTrace();
        }
    }

    @Override
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return handleInternal(request, response, (HandlerMethod)handler);
    }

    private ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handler) {
        ModelAndView mv = null;
//        Method method = handler.getMethod();
//        Object obj = handler.getBean();
//        Object objResult = null;
//        try {
//            objResult  = method.invoke(obj);
//        } catch (IllegalAccessException e) {
//            e.printStackTrace();
//        } catch (InvocationTargetException e) {
//            e.printStackTrace();
//        }
//        try {
//            response.getWriter().append(objResult.toString());
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
        try {
            invokeHandlerMethod(request, response, handler);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return mv;
    }

    protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
        ModelAndView mav = null;
        WebDataBinderFactory binderFactory = new WebDataBinderFactory();
        Parameter[] methodParameters = handlerMethod.getMethod().getParameters();
        Object[] methodParamObjs = new Object[methodParameters.length];
        // 对调用方法里的每一个参数，处理绑定
        int i = 0;
//        for (Parameter methodParameter : methodParameters) {
//            Object methodParamObj = methodParameter.getType().getDeclaredConstructor().newInstance();
//            // 给这个参数创建 WebDataBinder
//            WebDataBinder wdb = binderFactory.createBinder(request, methodParamObj, methodParameter.getName());
//            wbi.initBinder(wdb);
//            wdb.bind(request);
//            methodParamObjs[i] = methodParamObj;
//            i++;
//        }
        for (Parameter methodParameter : methodParameters) {
            if (methodParameter.getType()!=HttpServletRequest.class && methodParameter.getType()!=HttpServletResponse.class) {
                Object methodParamObj = methodParameter.getType().getDeclaredConstructor().newInstance();
                WebDataBinder wdb = binderFactory.createBinder(request, methodParamObj, methodParameter.getName());
                wbi.initBinder(wdb);
                wdb.bind(request);
                methodParamObjs[i] = methodParamObj;
            }
            else if (methodParameter.getType()==HttpServletRequest.class) {
                methodParamObjs[i] = request;
            }
            else if (methodParameter.getType()==HttpServletResponse.class) {
                methodParamObjs[i] = response;
            }
            i++;
        }
        Method invocableMethod = handlerMethod.getMethod();

//        Class<?> clz = handlerMethod.getBean().getClass();
//        Field[] fields = clz.getDeclaredFields();
//        for (Field field : fields) {
//            boolean isAutowired = field.isAnnotationPresent(Autowired.class);
//            if (isAutowired) {
//                field.setAccessible(true);
//                System.out.println(field.get(handlerMethod.getBean()));
//            }
//        }

        Object resultObj = invocableMethod.invoke(handlerMethod.getBean(), methodParamObjs);
        if (invocableMethod.isAnnotationPresent(ResponseBody.class)) {
            // 如果是ResponseBody注解，仅仅返回值，转换数据格式后直接写到response
            this.messageConverter.write(resultObj, response);
        } else { // 返回前端页面
            if (resultObj instanceof ModelAndView) {
                mav = (ModelAndView) resultObj;
            } else if (resultObj instanceof String) {
                // 字符串也认为是前端页面
                String sTarget = (String) resultObj;
                mav = new ModelAndView();
                mav.setViewName(sTarget);
            }
        }
//        response.getWriter().append(resultObj.toString());
        return mav;
    }

    public WebBindingInitializer getWebBindingInitializer() {
        return wbi;
    }

    public void setWebBindingInitializer(WebBindingInitializer wbi) {
        this.wbi = wbi;
    }

    public HttpMessageConverter getMessageConverter() {
        return messageConverter;
    }

    public void setMessageConverter(HttpMessageConverter messageConverter) {
        this.messageConverter = messageConverter;
    }
}
